﻿using System;
using System.Collections.Specialized;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;

namespace WebAssertTestLibrary.Core
{
    public abstract class W3CValidator
    {
        public string ValidatorUrl { get; set; }
        protected abstract EventWaitHandle Blocker { get; }

        protected static void ResetW3CBlocker(object state)
        {
            // Ensures that W3C Validator service is not called more than once a second
            Thread.Sleep(1000);
            ((EventWaitHandle)state).Set();
        }

        static readonly TimeSpan DefaultTimeout = new TimeSpan(0, 2, 30);

        protected virtual WebClient GetWebClient()
        {
            return new WebClientWithTimeout { Timeout = DefaultTimeout, Encoding = Encoding.UTF8 };
        }

        protected W3CValidityCheckResult IsValid(WebClient wc, string payload)
        {
            var result = new W3CValidityCheckResult();
            var w3cResponseHeaders = new WebHeaderCollection();

            var values = PrepareW3CRequest(payload);
            result.Body = SendW3CRequest(w3cResponseHeaders, wc, ValidatorUrl, values, Blocker);

            return ExtractW3CResult(result, w3cResponseHeaders);
        }

        protected abstract NameValueCollection PrepareW3CRequest(string payload);
        
        protected abstract string SendW3CRequest(WebHeaderCollection w3cResponseHeaders, WebClient wc, string url, NameValueCollection values, EventWaitHandle blocker);

        private static W3CValidityCheckResult ExtractW3CResult(W3CValidityCheckResult result, WebHeaderCollection w3CResponseHeaders)
        {
            if (w3CResponseHeaders.AllKeys.Contains("X-W3C-Validator-Warnings"))
            {
                int warnings;
                result.ParsedSuccessully = int.TryParse(w3CResponseHeaders["X-W3C-Validator-Warnings"], out warnings);
                result.WarningsCount = warnings;
                if (!result.ParsedSuccessully) return result;
            }
            if (w3CResponseHeaders.AllKeys.Contains("X-W3C-Validator-Errors"))
            {
                int errors;
                result.ParsedSuccessully = int.TryParse(w3CResponseHeaders["X-W3C-Validator-Errors"], out errors);
                result.ErrorsCount = errors;
                if (!result.ParsedSuccessully) return result;
            }

            string status = w3CResponseHeaders["X-W3C-Validator-Status"];
            if (!String.IsNullOrEmpty(status))
            {
                result.IsValid = (status.Equals("Valid", StringComparison.InvariantCultureIgnoreCase));
            }
            else
            {
                result.ParsedSuccessully = false;
            }

            return result;
        }
    }
}